package com.heo.sso.client.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Author 刘康
 * @Date 2020-08-13 10:47
 * @Description
 * @Revision
 **/
@Slf4j
public class LoginFilter implements Filter {

    private String ssoUrl;


    /**
     * 1. key: token   value: username
     * 2. key: ticket  value: token
     */
    public static Map<String, String> redis = new HashMap<>();

    public LoginFilter(String ssoUrl) {
        this.ssoUrl = ssoUrl;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        String loginUrl = ssoUrl + "?service=" + req.getRequestURL().toString();

        log.info("认证开始，ssoUrl:{}", ssoUrl);

        if (ssoUrl == null || ssoUrl.equals("")) {
            log.info("~~~~~~~~~~~~");
            resp.sendError(500);
            return;
        }

        String token = null;
        // 判断是否存在token
        log.info("1. 判断是否存在token");
        Cookie[] cookies = req.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if ("token".equals(cookies[i].getName())) {
                    token = cookies[i].getValue();
                    break;
                }
            }
        }

        if (token != null) {
            log.info("token: {}", token);
            String username = redis.get(token);
            if (username == null) {
                log.error("token无效 {}", token);
                // 清除cookie
                log.info("清除cookie");
                Cookie cookie = new Cookie("token", "");
                cookie.setMaxAge(0);
                resp.addCookie(cookie);
            } else {
                log.info(username + "访问系统");
                // 把token放到header中，方便后续获取
                log.info("2. 把token放到请求体中");
                request.setAttribute("token", token);
                log.info("~~~~~~~~~~~~");
                filterChain.doFilter(request, response);
                return;
            }
        } else {
            log.info("无token,用户未登录本系统");
        }

        // 判断是否携带ticket
        log.info("2. 判断是否携带ticket");
        String ticket = req.getParameter("ticket");
        if (ticket == null || ticket.equals("")) {
            log.info("ticket为空");
            log.info("用户未登录，重定向到登录页面");
            log.info("登录url:{}", loginUrl);
            log.info("~~~~~~~~~~~~");
            resp.sendRedirect(loginUrl);
            return;
        }
        log.info("ticket: {}", ticket);

        // 验证ticket是否有效
        log.info("3.验证ticket是否有效");
        RestTemplate restTemplate = new RestTemplate();
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        paramMap.add("ticket", ticket);
        String service = req.getRequestURL().toString();
        paramMap.add("service", service);
        log.info("service: {}", service);

        try {
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(ssoUrl + "/auth", paramMap, String.class);
            log.info("POST " + ssoUrl + " " + responseEntity.getStatusCodeValue());
            log.info("ticket有效");

            String username = responseEntity.getBody();
            log.info("username:{}", username);

            //单点登录成功,生成系统token,存放到cookie中
            token = UUID.randomUUID().toString();

            log.info("4. redis保存token和用户信息");
            redis.put(token, username);
            redis.put(ticket, token);

            log.info("5. token存放到cookie中");
            Cookie cookie = new Cookie("token", token);
            resp.addCookie(cookie);

            // 把token放到header中，方便后续获取
            log.info("6. 把token放到请求体中");
            request.setAttribute("token", token);

            log.info("~~~~~~~~~~~~");

            filterChain.doFilter(request, response);
        } catch (HttpClientErrorException e) {
            log.info("POST " + ssoUrl + " " + e.getStatusCode().value());
            log.info("用户ticket无效，重新登录");
            log.info("~~~~~~~~~~~~");
            resp.sendRedirect(loginUrl);
        }

    }
}

